package com.sweet.imserver.dao;

import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.db.sql.SqlLog;
import com.sweet.imserver.model.Member;
import com.sweet.imserver.utils.SQLUtils;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Promise;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.eventbus.Message;
import io.vertx.core.impl.logging.Logger;
import io.vertx.core.impl.logging.LoggerFactory;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.mysqlclient.MySQLConnectOptions;
import io.vertx.mysqlclient.MySQLPool;
import io.vertx.sqlclient.*;

public class DaoVerticle extends AbstractVerticle {

  private final Logger logger = LoggerFactory.getLogger(DaoVerticle.class);
  public static final String LOGIN_ADDRESS = "member.login";
  public static final String REGISTER_ADDRESS = "member.register";
  public static final String ADD_FRIEND_ADDRESS = "member.friend.apply";
  public static final String ADD_FRIEND_STATUS_ADDRESS = "member.friend.apply.status";
  public static final String QUERY_FRIEND_APPLY_ADDRESS = "member.friend.apply.query";
  public static final String FRIENDS_ADDRESS = "member.friend";
  public static final String MID_ADDRESS = "member.id";
  public static final String SEARCH_ADDRESS = "member.search.phone";
  public static final String FRIEND_CHAT_LIST_ADDRESS = "member.chat.list";
  public static final String FRIEND_CHAT_MESSAGE_LIST_ADDRESS = "member.chat.message.list";

  public static final String SAVE_MSG_ADDRESS = "im.mgs.save";

  private MySQLPool client;

  @Override
  public void start(Promise<Void> startPromise) throws Exception {
    MySQLConnectOptions connectOptions = new MySQLConnectOptions()
      .setPort(3306)
      .setHost("localhost")
      .setDatabase("sweet_im")
      .setUser("root")
      .setPassword("w123456!");
    PoolOptions poolOptions = new PoolOptions()
      .setMaxSize(5);
    client = MySQLPool.pool(vertx, connectOptions, poolOptions);

    EventBus eventBus = vertx.eventBus();
    // 用户注册
    eventBus.localConsumer(REGISTER_ADDRESS, registerHandler());
    // 用户登录
    eventBus.localConsumer(LOGIN_ADDRESS, loginHandler());
    // 手机号搜索
    eventBus.localConsumer(SEARCH_ADDRESS, searchHandler());
    // 查询好友
    eventBus.localConsumer(FRIENDS_ADDRESS, queryFriendsHandler());
    // 添加好友, 创建申请记录
    eventBus.localConsumer(ADD_FRIEND_ADDRESS, addFriendHandler());
    // 查询添加好友记录
    eventBus.localConsumer(QUERY_FRIEND_APPLY_ADDRESS, queryApplyFriendHandler());
    // 处理好友申请记录
    eventBus.localConsumer(ADD_FRIEND_STATUS_ADDRESS, applyFriendStatusHandler());
    // 查询最近好友聊天列表
    eventBus.localConsumer(FRIEND_CHAT_LIST_ADDRESS, queryFriendChatListHandler());
    // 查询好友聊天消息
    eventBus.localConsumer(FRIEND_CHAT_MESSAGE_LIST_ADDRESS, queryFriendMessageListHandler());

    // 保存消息记录
    eventBus.localConsumer(SAVE_MSG_ADDRESS, saveMsgHandler());

    startPromise.complete();
  }

  private Handler<Message<JsonObject>> queryFriendMessageListHandler() {
    return msg -> {
      String mid = msg.body().getString("mid");
      String fid = msg.body().getString("fid");
      Integer start = msg.body().getInteger("start");
      Integer length = msg.body().getInteger("length");

      client.preparedQuery(SQLUtils.to("select content, id, img, ctime, rid, sid, idkey from t_message where idkey = ? order by id desc limit ?, ?"))
        .execute(SQLUtils.tuple(fid.compareTo(mid) > 0 ? fid + "-" + mid : mid + "-" + fid, start, length))
        .onComplete(res -> {
          if (res.succeeded()) {
            JsonArray array = new JsonArray();
            for (Row row : res.result()) {
              array.add(row.toJson().put("id", row.getLong("id").toString())
                .put("rid", row.getLong("rid").toString())
                .put("sid", row.getLong("sid").toString())
              );
            }
            msg.reply(array);
          } else {
            msg.fail(-1, res.cause().getMessage());
          }
        });
    };
  }

  private Handler<Message<String>> queryFriendChatListHandler() {
    return msg -> {
      String mid = msg.body();
      client.preparedQuery(SQLUtils.to("select r.id as id, r.ctime as ctime, r.content as content, m.id as fid, m.name as friendName " +
        "from t_chat_record r, t_member m where r.fid = m.id and mid = ? " +
        "order by r.ctime desc"))
        .execute(SQLUtils.tuple(Long.parseLong(mid)))
        .onComplete(res -> {
          if (res.succeeded()) {
            JsonArray array = new JsonArray();
            for (Row row : res.result()) {
              array.add(row.toJson().put("id", row.getLong("id").toString())
                .put("fid", row.getLong("fid").toString()));
            }
            msg.reply(array);
          } else {
            msg.fail(-1, res.cause().getMessage());
          }
        });
    };
  }

  private Handler<Message<JsonObject>> saveMsgHandler() {
    return msg -> {
      JsonObject body = msg.body();
      // 接受人
      Long rid = Long.parseLong(body.getString("rid"));
      // 发送人
      Long sid = Long.parseLong(body.getString("sid"));
      String content = body.getString("content");
      long ctime = System.currentTimeMillis();

      client.withTransaction(tx -> tx.preparedQuery(SQLUtils.to("insert into t_message (id, img, ctime, content, rid, sid, idkey) VALUES (?,?,?,?,?,?,?)"))
        .execute(SQLUtils.tuple(IdUtil.getSnowflakeNextId(), "", ctime, content, rid, sid,
          rid > sid ? rid + "-" + sid : sid + "-" + rid))
        .compose(res -> tx.preparedQuery(SQLUtils.to("select id, mid, fid, content, ctime from t_chat_record where mid = ? and fid = ? limit 1"))
          .execute(SQLUtils.tuple(sid, rid)))
        .compose(res -> {
          if (res.size() > 0) {
            Row next = res.iterator().next();
            Long id = next.getLong("id");
            String shortContent = content.length() > 100 ? content.substring(100) : content;
            return tx.preparedQuery(SQLUtils.to("update t_chat_record set content = ?, ctime = ? where id = ?"))
              .execute(SQLUtils.tuple(shortContent, ctime, id));
          }
          return tx.preparedQuery(SQLUtils.to("insert into t_chat_record (id, mid, fid, content, ctime) VALUES (?,?,?,?,?)"))
            .execute(SQLUtils.tuple(IdUtil.getSnowflakeNextId(), sid, rid, content, ctime));
        })
        .onComplete(res -> {
          if (res.succeeded()) {
            logger.debug("msg save success");
          } else {
            logger.error("msg save err", res.cause());
          }
        }));
    };
  }

  private Handler<Message<String>> queryFriendsHandler() {
    return msg -> {
      String mid = msg.body();
      client.preparedQuery(SQLUtils.to("select m.id as id, m.gender as gender, " +
        "m.name as name, m.phone as phone " +
        "from t_friends f, t_member m " +
        "where f.fid = m.id and f.mid = ?;"))
        .execute(SQLUtils.tuple(Long.parseLong(mid)))
        .onComplete(res -> {
          if (res.succeeded()) {
            JsonArray list = new JsonArray();
            for (Row row : res.result()) {
              JsonObject entries = row.toJson();
              entries.put("id", entries.getLong("id").toString());
              list.add(entries);
            }
            msg.reply(list);
          } else {
            msg.fail(-1, res.cause().getMessage());
          }
        });
    };
  }

  private Handler<Message<JsonObject>> applyFriendStatusHandler() {
    return msg -> {
      JsonObject body = msg.body();
      long id = Long.parseLong(body.getString("id"));
      long mid = Long.parseLong(body.getString("mid"));
      // 是否同意：0 未处理 1 同意 2 不同意
      Integer agree = body.getInteger("agree");
      client.withTransaction(tx -> tx.preparedQuery(SQLUtils.to("select id, fid, agree from t_friends_record where id = ?;"))
        .execute(SQLUtils.tuple(id))
        .compose(f -> {
          Row next = f.iterator().next();
          Integer agree1 = next.getInteger("agree");
          Long fid = next.getLong("fid");
          if (agree1 == 0) {
            return tx.preparedQuery(SQLUtils.to("update t_friends_record set agree = ? where id = ? and mid = ?;"))
              .execute(SQLUtils.tuple(agree, id, mid))
              .compose(c -> {
                if (agree == 1) {
                  return tx.preparedQuery(SQLUtils.to("insert into t_friends (id, mid, fid) VALUES (?,?,?);"))
                    .execute(SQLUtils.tuple(IdUtil.getSnowflakeNextId(), mid, fid));
                } else {
                  return Future.succeededFuture();
                }
              });
          } else {
            return Future.succeededFuture();
          }
        })).onComplete(res -> {
        if (res.succeeded()) {
          msg.reply(new JsonObject());
        } else {
          msg.fail(-1, res.cause().getMessage());
        }
      });

    };
  }

  private Handler<Message<JsonObject>> queryApplyFriendHandler() {
    return msg -> {
      JsonObject body = msg.body();
      // 当前人id
      Long id = Long.parseLong(body.getString("id"));
      client.preparedQuery(SQLUtils.to("select r.id as id, r.note as note, r.ctime as ctime, r.agree as agree," +
        " m.name as name, m.gender as gender" +
        " from t_friends_record r, t_member m where r.fid = m.id and r.mid = ? order by id;"))
        .execute(SQLUtils.tuple(id))
        .onComplete(res -> {
          if (res.succeeded()) {
            JsonArray array = new JsonArray();
            for (Row row : res.result()) {
              JsonObject value = row.toJson();
              value.put("id", value.getLong("id").toString());
              array.add(value);
            }
            msg.reply(array);
          } else {
            msg.fail(-1, res.cause().getMessage());
          }
        });
    };
  }

  private Handler<Message<JsonObject>> addFriendHandler() {
    return msg -> {
      JsonObject body = msg.body();
      // 当前人id
      String id = body.getString("id");
      // 要添加的朋友id
      String fid = body.getString("fid");
      // 添加好友的备注信息
      String note = body.getString("note");
      // 好友列表
      client.preparedQuery(SQLUtils.to("insert into t_friends_record (id, mid, fid, note, ctime) VALUES (?,?,?,?,?);"))
        .execute(SQLUtils.tuple(IdUtil.getSnowflakeNextId(), Long.parseLong(id),
          Long.parseLong(fid), note, (int) (System.currentTimeMillis() / 1000)))
        .onComplete(res -> {
          if (res.succeeded()) {
            msg.reply(true);
          } else {
            msg.fail(-1, res.cause().getMessage());
          }
        });
    };
  }


  private Handler<Message<JsonObject>> searchHandler() {
    return msg -> {
      JsonObject body = msg.body();
      String phone = body.getString("phone");
      Long memberId = body.getLong("mid");

      client.preparedQuery(SQLUtils.to("select id, name, phone, gender from t_member where phone = ? limit 1"))
        .execute(SQLUtils.tuple(phone))
        .compose(res -> {
          if (res.size() == 0) {
            return Future.succeededFuture(new JsonObject());
          }
          Row row = res.value().iterator().next();
          return Future.succeededFuture(row.toJson());
        })
        .compose(res -> {
          if (res.isEmpty()) {
            return Future.succeededFuture(res);
          }
          Long id = res.getLong("id");
          // 检查查询的手机号，是否已经是自己的好友了
          Future<RowSet<Row>> execute = client.preparedQuery(SQLUtils.to("select count(*) count from t_friends where mid = ? and fid = ?"))
            .execute(SQLUtils.tuple(memberId, id));
          return execute.compose(r -> {
            Integer count = r.iterator().next().getInteger("count");
            return Future.succeededFuture(new JsonObject()
              .put("f", res.put("id", id.toString()))
              .put("exist", count != null && count >= 1));
          });
        })
        .onComplete(res -> {
          if (res.succeeded()) {
            msg.reply(res.result());
          } else {
            logger.error("searchHandlerErr", res.cause());
            msg.fail(-1, res.cause().getMessage());
          }
        });
    };
  }

  private Handler<Message<JsonObject>> loginHandler() {
    return msg -> {
      JsonObject bodyAsJson = msg.body();
      String phone = bodyAsJson.getString("phone");
      String password = bodyAsJson.getString("password");
      Future<RowSet<Row>> rowSetFuture = client.preparedQuery(SQLUtils.to("select id, name, phone, password, gender from t_member where phone = ? limit 1;"))
        .execute(SQLUtils.tuple(phone));

      rowSetFuture.onSuccess(res -> {
        for (Row re : res) {
          if (DigestUtil.sha256Hex(password).equals(re.getString("password"))) {
            JsonObject json = re.toJson();
            json.remove("password");
            msg.reply(json);
            return;
          }
        }
        msg.fail(-1, "账号或密码错误");
      });

      rowSetFuture.onFailure(fail -> {
        logger.error("query err", fail);
        msg.fail(-1, fail.getMessage());
      });
    };
  }

  private Handler<Message<JsonObject>> registerHandler() {
    return msg -> {
      JsonObject body = msg.body();
      final Member member = Member.fromJson(body);
      client.withTransaction(conn -> {
        Future<RowSet<Row>> future = conn.preparedQuery(SQLUtils.to("select count(*) as count from t_member where phone = ? limit 1;"))
          .execute(SQLUtils.tuple(member.getPhone()));
        return future.compose(r -> {
          for (Row row : r) {
            int count = row.getInteger("count");
            if (count >= 1) {
              return Future.succeededFuture(false);
            }
          }
          PreparedQuery<RowSet<Row>> insertQuery = conn.preparedQuery(SQLUtils.to("insert into t_member (id, name, phone, password, gender) values (?, ?, ?, ?, ?)"));
          Future<RowSet<Row>> insertExecute = insertQuery.execute(SQLUtils.tuple(member.getId(),
            member.getName(), member.getPhone(), member.getPassword(), member.getGender()));
          return insertExecute.compose(insertRes -> Future.succeededFuture(true));
        });
      }).onSuccess(res -> {
        if (res) {
          msg.reply(member.getId().toString());
        } else {
          msg.fail(-1, "手机号已经注册了");
        }
      }).onFailure(fail -> msg.fail(-1, fail.getMessage()));
    };
  }

}
